package com.kamistoat.meimeimall.meimeimallproduct.thread;

import java.util.concurrent.*;

/**
 * 用于测试多线程
 */
public class ThreadTest {
    /**
     * 在main函数中测试多线程类
     *
     * @param args
     */
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println("main...start...");

        // 直接新定义一个Thread01类。用.start()方法执行
        // 可以发现main和thread01是异步的，main并没有等待thread01
        Thread01 thread01 = new Thread01();
        thread01.start();

        // Runnable异步需要用new Thread(Runnable接口实现类)来定义
        Thread Runnable01 = new Thread(new Runnable01());
        Runnable01.start();

        // Callable需要先封装成FutureTask
        FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
        // 然后用new Thread(FutureTask)来定义
        Thread Callable01 = new Thread(futureTask);
        Callable01.start();
        // 使用FutureTask.get()可以在这条异步任务执行完成后，获取到任务的返回值
        // 注意，FutureTask的等待是阻塞等待。一旦使用了这条命令，整个main方法一定会等待异步任务。
        Integer futureTaskResult = futureTask.get();

        // 使用 可以获取返回值的.submit()方法 和 不能获取返回值的.execute()方法
        servicePool.execute(new Runnable01());

        System.out.println("main...end...");
    }

    /**
     * 方法一：继承thread类并重写run方法
     */
    public static class Thread01 extends Thread {
        // 覆写run方法
        @Override
        public void run() {
            // 使用Thread.currentThread()获取当前线程
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Thread01:" + i);
        }
    }

    /**
     * 方法二：实现Runnable接口并重写run方法
     */
    public static class Runnable01 implements Runnable {
        // 覆写run方法
        @Override
        public void run() {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Runnable01:" + i);
        }
    }

    /**
     * 方法三：实现Callable<?>接口，<?>是这个接口的实现类的方法要返回的数据类型
     * Callable接口要求覆写call()方法，这个方法的返回值就是<?>中的内容。
     */
    public static class Callable01 implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            System.out.println("当前线程：" + Thread.currentThread().getId());
            int i = 10 / 2;
            System.out.println("Callab01:" + i);
            return i;
        }
    }

    /**
     * 方法四：直接给线程池提价任务
     */
    // 创建线程池。注意，线程池的数量一定要控制，最好在3个以内。
    // 创建一个分配10个线程的线程池，异步任务直接提交给线程池。超过线程池大小的话，提交的异步任务会阻塞，直到线程池空出空闲线程
    // 所以线程池多大应该取决于项目能同时容纳多少个异步任务
    public static ExecutorService servicePool = Executors.newFixedThreadPool(10);

    ThreadPoolExecutor pool = new ThreadPoolExecutor(5,
            200,
            10,
            TimeUnit.SECONDS,
            new LinkedBlockingDeque<>(5000),
            Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());
}
